///mixin : 从个人理解来看，可以把它想象为Kotlin中的接口(和Java的区别是可以带非抽象的属性和方法)，而多个mixin可以相互覆盖以实现组合

mixin TestMixin {
  void test() {
    print('test');
  }

  int testInt = 1;

  void test2();
}

class Test with TestMixin {
  @override
  test2() {
    print('test2');
  }
}

void test1() {
  Test().test(); // test
  print(Test().testInt); // 1
  Test().test2(); // test2
}

//////////////////////////////////////////////////////////////////////////////////
//mixin本身可以是抽象的，可以定义各种方法属性，等后续类去实现
class BaseObject {
  void method() {
    print('call method');
  }
}

mixin TestMixin2 on BaseObject {
  void test() {
    print('test');
  }

  int testInt = 1;

  void test2() {
    method();
  }
}

class Test2 extends BaseObject with TestMixin {
  @override
  void test2() {
    print('Test2:test2');
  }
}

void test2() {
  Test2().test(); // test
  print(Test2().testInt); // 1
  Test2().test2(); // call method
}

//////////////////////////////////////////////////////////////////////////////////
mixin TestMixin3 {
  void test() {
    print('test');
  }

  int testInt = 1;

  void test2();
}

mixin TestMixin3_1 {
  int testInt = 2;

  void test3() {
    print('test3');
  }
}

class Test3 with TestMixin3, TestMixin3_1 {
  @override
  test2() {
    print('test2');
  }
}

void test3() {
  Test3().test(); // test
  print(Test3().testInt); // 2
  Test3().test2(); // test2
  Test3().test3(); // test3
}

///如果mixin存在冲突的部分，后面会覆盖前面的，没有冲突的则会保留，所以可以存在后面的mixin修改了前面的mixin的一部分逻辑的情况，
///不需要直接继承即可实现覆盖，避免了更复杂的继承关系

//////////////////////////////////////////////////////////////////////////////////

mixin TestMixin4 on BaseClass {
  void init() {
    print('TestMixin init start');
    super.init();
    print('TestMixin init end');
  }
}

mixin TestMixin4_1 on BaseClass {
  void init() {
    print('TestMixin2 init start');
    super.init();
    print('TestMixin2 init end');
  }
}

class BaseClass {
  void init() {
    print('Base init');
  }

  BaseClass() {
    init();
  }
}

class TestClass4 extends BaseClass with TestMixin4, TestMixin4_1 {
  @override
  void init() {
    print('TestClass init start');
    super.init();
    print('TestClass init end');
  }

  @override
  void method() {
    print('TestClass method');
  }
}

void test4() {
  TestClass4();

  /// TestClass init start
  /// TestMixin2 init start
  /// TestMixin init start
  /// Base init
  /// TestMixin init end
  /// TestMixin2 init end
  /// TestClass init end
}

//////////////////////////////////////////////////////////////////////////////////

main() {
  test1();
  test2();
  test3();
  test4();
}
